#include "gd32f30x.h"
#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "DevicesFlash.h"
#include "DevicesSPIFlash.h"
#include "disk_virtual.h"


/* 分区表 */
#define MBR_BLOCK_ADDR              0x00000000
#define MBR_BLOCK_NUM               (4096 / DISK_VIRTUAL_BLOCK_SIZE)

#define Partition_1_BLOCK_ADDR      (MBR_BLOCK_ADDR + MBR_BLOCK_NUM)
#define Partition_1_BLOCK_NUM       (1024 * 1024 * 32 / DISK_VIRTUAL_BLOCK_SIZE)

#define Partition_2_BLOCK_ADDR      (Partition_1_BLOCK_ADDR + Partition_1_BLOCK_NUM)
#define Partition_2_BLOCK_NUM       (1024 * 1024 * 32 / DISK_VIRTUAL_BLOCK_SIZE)

#define Partition_3_BLOCK_ADDR      (Partition_2_BLOCK_ADDR + Partition_2_BLOCK_NUM)
#define Partition_3_BLOCK_NUM       (1024 * 1024 * 32 / DISK_VIRTUAL_BLOCK_SIZE)

#define Partition_4_BLOCK_ADDR      (Partition_3_BLOCK_ADDR + Partition_3_BLOCK_NUM)
#define Partition_4_BLOCK_NUM       (1024 * 1024 * 32 / DISK_VIRTUAL_BLOCK_SIZE)


/* FAT文件系统 */
#define DBR_CLUSTER_SIZE            4096
#define DBR_SIZE                    DBR_CLUSTER_SIZE
#define FAT_SIZE                    (Partition_1_BLOCK_NUM * DISK_VIRTUAL_BLOCK_SIZE / DBR_CLUSTER_SIZE * 2)    /* 至少需要：磁盘大小 / 簇 * 2 */
#define DIR_NUM                     512

#define DBR_ADDR                    0x00000000
#define FAT_ADDR                    (DBR_ADDR + DBR_SIZE)
#define DIR_ADDR                    (FAT_ADDR + FAT_SIZE)
#define FILE_CMD_ADDR               (DIR_ADDR + DIR_NUM * 32)           /* 一条目录信息占32Byte */
#define FILE_DATA_ADDR              (FILE_CMD_ADDR + DBR_CLUSTER_SIZE)  /* 一个文件最小占一个簇 */


const static uint8_t MBR[] = {
    /* 分区1信息 */
    /* 0x80：活动分区、0x00非活动分区 */
    [0x1BE] = 0x00,
    /* 使用LBA寻址，所以此处设置为0xFFFFFF */
    [0x1BF] = 0xFE, 0xFF, 0xFF,
    /* 0x06：FAT16、0x01：FAT32 */
    [0x1C2] = 0x06,
    /* 使用LBA寻址，所以此处设置为0xFFFFFF */
    [0x1C3] = 0xFE, 0xFF, 0xFF,
    /* LBA寻址 */
    [0x1C6] = (uint8_t)Partition_1_BLOCK_ADDR, (uint8_t)(Partition_1_BLOCK_ADDR >> 8), (uint8_t)(Partition_1_BLOCK_ADDR >> 16), (uint8_t)(Partition_1_BLOCK_ADDR >> 24),
    [0x1CA] = (uint8_t)Partition_1_BLOCK_NUM,  (uint8_t)(Partition_1_BLOCK_NUM >> 8),  (uint8_t)(Partition_1_BLOCK_NUM >> 16),  (uint8_t)(Partition_1_BLOCK_NUM >> 24),

//    /* 分区2地址信息 */
//    /* 0x80：活动分区、0x00非活动分区 */
//    [0x1CE] = 0x00,
//    /* 使用LBA寻址，所以此处设置为0xFFFFFE */
//    [0x1CF] = 0xFE, 0xFF, 0xFF,
//    /* 0x06：FAT16、0x01：FAT32 */
//    [0x1D2] = 0x06,
//    /* 使用LBA寻址，所以此处设置为0xFFFFFE */
//    [0x1D3] = 0xFE, 0xFF, 0xFF,
//    /* LBA寻址 */
//    [0x1D6] = (uint8_t)Partition_2_BLOCK_ADDR, (uint8_t)(Partition_2_BLOCK_ADDR >> 8), (uint8_t)(Partition_2_BLOCK_ADDR >> 16), (uint8_t)(Partition_2_BLOCK_ADDR >> 24),
//    [0x1DA] = (uint8_t)Partition_2_BLOCK_NUM,  (uint8_t)(Partition_2_BLOCK_NUM >> 8),  (uint8_t)(Partition_2_BLOCK_NUM >> 16),  (uint8_t)(Partition_2_BLOCK_NUM >> 24),
//    
//    /* 分区3地址信息 */
//    /* 0x80：活动分区、0x00非活动分区 */
//    [0x1DE] = 0x00,
//    /* 使用LBA寻址，所以此处设置为0xFFFFFE */
//    [0x1DF] = 0xFE, 0xFF, 0xFF,
//    /* 0x06：FAT16、0x01：FAT32 */
//    [0x1E2] = 0x06,
//    /* 使用LBA寻址，所以此处设置为0xFFFFFE */
//    [0x1E3] = 0xFE, 0xFF, 0xFF,
//    /* LBA寻址 */
//    [0x1E6] = (uint8_t)Partition_3_BLOCK_ADDR, (uint8_t)(Partition_3_BLOCK_ADDR >> 8), (uint8_t)(Partition_3_BLOCK_ADDR >> 16), (uint8_t)(Partition_3_BLOCK_ADDR >> 24),
//    [0x1EA] = (uint8_t)Partition_3_BLOCK_NUM,  (uint8_t)(Partition_3_BLOCK_NUM >> 8),  (uint8_t)(Partition_3_BLOCK_NUM >> 16),  (uint8_t)(Partition_3_BLOCK_NUM >> 24),

//    /* 分区4地址信息 */
//    /* 0x80：活动分区、0x00非活动分区 */
//    [0x1EE] = 0x00,
//    /* 使用LBA寻址，所以此处设置为0xFFFFFE */
//    [0x1EF] = 0xFE, 0xFF, 0xFF,
//    /* 0x06：FAT16、0x01：FAT32 */
//    [0x1F2] = 0x06,
//    /* 使用LBA寻址，所以此处设置为0xFFFFFE */
//    [0x1F3] = 0xFE, 0xFF, 0xFF,
//    /* LBA寻址 */
//    [0x1F6] = (uint8_t)Partition_4_BLOCK_ADDR, (uint8_t)(Partition_4_BLOCK_ADDR >> 8), (uint8_t)(Partition_4_BLOCK_ADDR >> 16), (uint8_t)(Partition_4_BLOCK_ADDR >> 24),
//    [0x1FA] = (uint8_t)Partition_4_BLOCK_NUM,  (uint8_t)(Partition_4_BLOCK_NUM >> 8),  (uint8_t)(Partition_4_BLOCK_NUM >> 16),  (uint8_t)(Partition_4_BLOCK_NUM >> 24),

    [510] = 0x55, [511] = 0xAA,
};

const static uint8_t DBR1[] = {
    /* JUMP 指令 */
    0xEB, 0x3C, 0x90,
    /* OEM 厂商标志 */
    [0x03] = 'M',  'S',  'D',  'O',  'S',  '5',  '.',  '0',
    /* 扇区字节数 */
    [0x0B] = (uint8_t)DISK_VIRTUAL_BLOCK_SIZE, (uint8_t)(DISK_VIRTUAL_BLOCK_SIZE >> 8),
    /* 每簇扇区数 */
    [0x0D] = DBR_CLUSTER_SIZE / DISK_VIRTUAL_BLOCK_SIZE,
    /* 保留扇区数（FAT之前的扇区数，包含DBR） */
    [0x0E] = (uint8_t)(DBR_SIZE / DISK_VIRTUAL_BLOCK_SIZE), (uint8_t)((DBR_SIZE / DISK_VIRTUAL_BLOCK_SIZE) >> 8),
    /* FAT个数 */
    [0x10] = 0x01,
    /* 根目录项数（一般为512） */
    [0x11] = (uint8_t)DIR_NUM, (uint8_t)(DIR_NUM >> 8),
    /* 小扇区数（为0时，由后面的大扇区决定） */
    [0x13] = 0x00, 0x00,
    /* 0xF8：硬盘、0xF0：软盘 */
    [0x15] = 0xF8,
    /* 每个FAT所占扇区数 */
    [0x16] = (uint8_t)(FAT_SIZE / DISK_VIRTUAL_BLOCK_SIZE), (uint8_t)((FAT_SIZE / DISK_VIRTUAL_BLOCK_SIZE) >> 8),
    /* 每磁道扇区数（sectors per trark） */
    [0x18] = 0x00, 0x00,
    /* 磁头数（number of head） */
    [0x1A] = 0x00, 0x00,
    /* 分区起始扇区地址 */
    [0x1C] = (uint8_t)Partition_1_BLOCK_ADDR, (uint8_t)(Partition_1_BLOCK_ADDR >> 8), (uint8_t)(Partition_1_BLOCK_ADDR >> 16), (uint8_t)(Partition_1_BLOCK_ADDR >> 24),
    /* 分区大小（大扇区数） */
    [0x20] = (uint8_t)Partition_1_BLOCK_NUM,  (uint8_t)(Partition_1_BLOCK_NUM >> 8),  (uint8_t)(Partition_1_BLOCK_NUM >> 16),  (uint8_t)(Partition_1_BLOCK_NUM >> 24),
    /* 0x80：硬盘、0x00：软盘 */
    [0x24] = 0x80,
    /* 保留 */
    [0x25] = 0x00,
    /* 0x28、或者0x29 */
    [0x26] = 0x29,
    /* 4Byte 随机数 */
    [0x27] =0x35, 0x39, 0x36, 0x33,
    [0x2B] = 'H',  'o',  'n',  'r',  'u',  'n',  ' ',  ' ',  ' ',  ' ',  ' ',
    [0x36] = 'F',  'A',  'T',  '1',  '6',  ' ',  ' ',  ' ',

    /* 0x3E - 0x1FD: Bootstrap code */
    [510] = 0x55, [511] = 0xAA,
};

const static uint8_t FAT[] = {
    0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};

const static uint8_t DIR[] = {
    'N',  'E',  'T',  'W',  'O',  'R',  'K',  0x20, 0x20, 0x20, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    'C',  'M',  'D',  0x20, 0x20, 0x20, 0x20, 0x20, 'T',  'X',  'T',  0x20, 0x00, 0x00, 0x00, 0x00,
    0x6A, 0x1A, 0xBE, 0x58, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x1A, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00,
    'D',  'A',  'T',  'A',  0x20, 0x20, 0x20, 0x20, 'T',  'X',  'T',  0x20, 0x00, 0x00, 0x00, 0x00,
    0x6A, 0x1A, 0xBE, 0x58, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x1A, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00,
};


int8_t cDiskVirtualWrite(uint32_t uiAddress, const void *pvBuff, int32_t iLength)
{
    uiAddress /= DISK_VIRTUAL_BLOCK_SIZE;

    /* Partition 1 */
    if((Partition_1_BLOCK_ADDR <= uiAddress) && (uiAddress < Partition_2_BLOCK_ADDR))
    {
        uiAddress -= Partition_1_BLOCK_ADDR;
        uiAddress *= DISK_VIRTUAL_BLOCK_SIZE;

        /* CMD.BIN (size: 4096Byte) */
        if((FILE_CMD_ADDR <= uiAddress) && (uiAddress < (FILE_CMD_ADDR + 4096)))
        {
            iLength = iLength < 4096 ? iLength : 4096;
        }
        /* DATA.BIN (size: 4096Byte) */
        else if((FILE_DATA_ADDR <= uiAddress) && (uiAddress < (FILE_DATA_ADDR + 4096)))
        {
            iLength = iLength < 4096 ? iLength : 4096;
        }
    }

    return 0;
}

int8_t cDiskVirtualRead(uint32_t uiAddress, void *pvBuff, int32_t iLength)
{
    memset(pvBuff, 0, iLength);

    uiAddress /= DISK_VIRTUAL_BLOCK_SIZE;

    /* MBR */
    if(uiAddress < Partition_1_BLOCK_ADDR)
    {
        if(uiAddress < sizeof(MBR))
        {
            iLength = iLength < sizeof(MBR) ? iLength : sizeof(MBR);
            memcpy(pvBuff, MBR, iLength);
        }
    }
    /* Partition x */
    else
    {
        /* Partition 1 */
        if(uiAddress < Partition_2_BLOCK_ADDR)
        {
            uiAddress -= Partition_1_BLOCK_ADDR;
            uiAddress *= DISK_VIRTUAL_BLOCK_SIZE;

            /* DBR */
            if((DBR_ADDR <= uiAddress) && (uiAddress < (DBR_ADDR + sizeof(DBR1))))
            {
                iLength = iLength < sizeof(DBR1) ? iLength : sizeof(DBR1);
                memcpy(pvBuff, DBR1, iLength);
            }
            /* FAT */
            else if((FAT_ADDR <= uiAddress) && (uiAddress < (FAT_ADDR + sizeof(FAT))))
            {
                iLength = iLength < sizeof(FAT) ? iLength : sizeof(FAT);
                memcpy(pvBuff, FAT, iLength);
            }
            /* DIR */
            else if((DIR_ADDR <= uiAddress) && (uiAddress < (DIR_ADDR + sizeof(DIR))))
            {
                iLength = iLength < sizeof(DIR) ? iLength : sizeof(DIR);
                memcpy(pvBuff, DIR, iLength);
            }
            /* CMD.BIN (size: 4096Byte) */
            else if((FILE_CMD_ADDR <= uiAddress) && (uiAddress < (FILE_CMD_ADDR + 4096)))
            {
                iLength = iLength < 4096 ? iLength : 4096;
            }
            /* DATA.BIN (size: 4096Byte) */
            else if((FILE_DATA_ADDR <= uiAddress) && (uiAddress < (FILE_DATA_ADDR + 4096)))
            {
                iLength = iLength < 4096 ? iLength : 4096;
            }
        }
        /* Partition 2 */
        else if(uiAddress < Partition_3_BLOCK_ADDR)
        {
            uiAddress -= Partition_2_BLOCK_ADDR;
            uiAddress *= DISK_VIRTUAL_BLOCK_SIZE;

            memcpy(pvBuff, (uint32_t *)(FLASH_BASE + uiAddress), iLength);
        }
        /* Partition 3 */
        else if(uiAddress < Partition_4_BLOCK_ADDR)
        {
            uiAddress -= Partition_3_BLOCK_ADDR;
            uiAddress *= DISK_VIRTUAL_BLOCK_SIZE;

            memcpy(pvBuff, (uint32_t *)(AHB3_BUS_BASE + uiAddress), iLength);
        }
        /* Partition 4 */
        else
        {
            uiAddress -= Partition_4_BLOCK_ADDR;
            uiAddress *= DISK_VIRTUAL_BLOCK_SIZE;

            cSPIFlashReadDatas(uiAddress, pvBuff, iLength);
        }
    }

    return 0;
}
